/**
 * jml预编译
 *
 */
(function(Helper) {
	"use strict";

	var elemIndex = 0,
		activePages = {},
		Jml = Ccay.Jml = {
			Const: {
				JID: '_jid'
			},
			getActivePage: function(pageID) {
				return activePages[pageID];
			},
			setActivePage: function(page) {
				this.activePage = page;
				activePages[page.id] = page;
			},
			removeActivePage: function(page) {
				activePages[page.id] = null;
			},
			newJID: function() {
				return Const.PREFIX + (elemIndex++);
			}
		},
		Const = {
			PREFIX: 'j',
			DATA_ATTR_REGEXP: /^data-/,
			OPTION_ATTR_REGEXP: /^option/,
			EVENT_ATTR_REGEXP: /^event/,
			EXT_ATTR_REGEXP: /^ext/,

			/**
			 * dom类型常量
			 */
			ELEMENT_NODE: 1,
			ATTRIBUTE_NODE: 2,
			TEXT_NODE: 3,
			CDATA_SECTION_NODE: 4,
			ENTITY_REFERENCE_NODE: 5,
			ENTITY_NODE: 6,
			PROCESSING_INSTRUCTION_NODE: 7,
			COMMENT_NODE: 8,
			DOCUMENT_NODE: 9,
			DOCUMENT_TYPE_NODE: 10,
			DOCUMENT_FRAGMENT_NODE: 11,
			NOTATION_NODE: 12,

			/**
			 * 匹配html标签的结束部分
			 *
			 * eg. </div>
			 */
			END_TAG_REGEXP: /<\s*\/\s*([\w:-]+)[^>]*>$/,

			/**
			 * 字符串中需要特殊处理的字符集
			 */
			formatSpaces: {
				'"': '"',
				"'": "'",
				'\\': '\\',
				'\r': 'r',
				'\n': 'n',
				'\t': 't',
				'\u2028': 'u2028',
				'\u2029': 'u2029'
			}
		};

	var EFactory = Jml.ElementFactory = $.IFactory({
		type: "object",
		mapping: {
			init: function(op) {
				this.builder = op.view.builder;
				this.page = op.view.page;
				this.parent = op.view;
				this.parentView = this.page.getCurrentView();

				this.domTemplate = op.domTemplate;

				this.config = new Jml.ConfigLoader(this.domTemplate, this.page);
				this._buildConfig();
			},
			_buildConfig: function() {
				this.config.compile();
			},
			/** 元素模板编译方法
			 */
			compile: function() {
				this._build();
			},
			/** 生成元素属性设置方法
			 */
			_build: function() {

			}

		},
		proto: {
			/** 
			 * 获取类型
			 */
			getElem: function(elemType, builder) {
				var elem = this.get(elemType);
				if (elem == null) {
					//					elem = {
					//						compile:$.noop
					//					};
					builder && builder.pushHtml("<div>" + elemType + "，未定义元素！</div>")
				}
				return elem;
			},
			/** 编译元素
			 * @param {string} elemType : 元素类型
			 * @param {jqDom} domTemplate : 模板对象
			 *  @param {object} view : 视图对象
			 *  @param {object} builder : 模板生成器对象
			 */
			compileElement: function(elemType, domTemplate, view) {
				var elem = this.getElem(elemType, view.builder);
				if (elem) {
					elem = new elem({
						domTemplate: domTemplate,
						view: view
					});
					elem.compile();
				}
			},
			addView: function(type, proto, parent, builder) {
				this.add(type, proto, parent || 'view');
			}
		}
	});

	EFactory.add("view", {
		_build: function() {
			this.config.buildHtmlAttr();
			var tagName = this.domTemplate[0].tagName;
			this.builder.pushHtml("<" + tagName + ' ' + this.config.htmlAttr.prop + ">");

			this._compileChildren();
			this.builder.pushHtml("</" + tagName + ">");
		},
		compile: function() {
			var view = this;
			//设置渲染模式
			view.renderType = view.config.prop.render || view.page.getCurrentRenderType();

			view.page.currentView.push(view);
			view._build();
			view.isInitCtr != false && view._attachInit();
			view.page.currentView.pop();
		},
		_compileChildren: function() {
			Jml.compileChildNodes(this);
		},
		_attachInit: function() {
			var elem = this;
			elem.page.fnBeforeLoad.add(function() {
				var page = this,
					config = elem.config,
					target = page.findElement(elem);

				config.execute();
				elem._initControl(target, config.option);
				//添加扩展小插件编译
				Jml.compileExt(target, config.ext);
				//执行初始化委托
				page.fireInitHandler(elem);
			});
		},
		_initControl: function(target, op) {
			if (this.controlName) {
				var ctr = target[this.controlName];
				ctr && ctr.call(target, op);
			}
		}
	})

	var viewStatus = {
		Compling: "compling",
		Init: "init",
		Load: "load",
		Request: "reqeust",
		Complete: "complete",
		AllCompete: "allComplete"
	}

	EFactory.add("page", {
		isInitCtr: false,
		init: function(op) {
			var page = this;
			$.extend(page, op);
			page.page = page;
			page.dom = $(page.target);

			page.builder = new FunctionBuilder();
			page.config = new Jml.ConfigLoader(page.domTemplate, page);
			page.id = page.config.jid;

			//初始化个阶段的委托方法
			page.fnReady = $.Callbacks();
			page.fnBeforeLoad = $.Callbacks();
			page.fnLoad = $.Callbacks();

			//动态运行函数的参数名数组
			page._innerArguments = ["page"];
			//动态运行函数的参数
			page._innerObject = [page];
			//
			page._InitHandler = $.IFactory();
			page._requestQueue = [];
		},
		addRequest: function(ajax) {
			this._requestQueue.push(ajax);
		},
		completeRequest: function(result, ajax) {
			if (--this._requestNum == 0) {
				this._load();
			}
		},
		compile: function() {
			Jml.activePage = this;
			this.currentView = [];
			this.callParent("compile");
			//this._build();
			this.currentView = null;
		},
		runHandler : function(handler){
			var page = this,callFn = page["on" + handler],
				delegate = page["fn" + handler];

			callFn && callFn(page);
			delegate && delegate.fireWith(page);
		},
		_build: function() {
			var page = this,
				html;
			page.status = viewStatus.Complie;
			//调用父类生成方法
			page.callParent("_build", [page]);

			//将方法生成器编译成模板方法
			if (page.template = page.builder.compile(this._innerArguments)) {
				html = page.callFn(page.template);
			}
			//清除dom模板
			page.domTemplate = null;
			page.status = viewStatus.Init;

			page._ready(page,html);
		},

		/**加载阶段**/
		_ready: function(page,html) {
			page.status = viewStatus.Load;
			//将生成的模板内容加载到目标对象中
			page.dom.html(html);

			page.runHandler("Ready");
			page._request(page);
		},
		/**请求阶段**/
		_request: function(page) {
			page._requestNum = page._requestQueue.length;
			if (page._requestNum) {
				//开启请求状态
				page.status = viewStatus.Request;
				$.each(page._requestQueue, function(i, ajax) {
					Ccay.Core._originalAjax(ajax);
				})
			} else
				page._load();
		},
		/**完成阶段**/
		_load: function() {
			Jml.activePage = null;
			var page = this;
			page.status = viewStatus.Complete;
			page.fnBeforeLoad.fireWith(page);
			page.runHandler("Load");

			//   			if(this._destoryObject.length) 
			//   			{
			//   				$.each(this._destoryObject,function(i,name){
			//   					view[name] = null;
			//   				});
			//   			}
			//   			this._innerArguments = this._innerObject = this._destoryObject = null;
		},
		/**设置视图对象方法
		 *  @param {object} op : 参数选项,op.name参数名
		 *  @param {object} obj : 参数对象
		 */
		setObject: function(op, obj) {
			this._innerArguments.push(op.name);
			this._innerObject.push(obj);
			//   			if(!op.durable)
			//   				this._destoryObject.push(op.name);
			//this[op.name] = obj;
			Helper.setObj(op.name, this, obj);
		},
		/** 使用view内置对象参数，将字符串编译成方法
		 *  @param {string} fnStr : 参数选项,op.name参数名
		 *  @param {boolean} fire : 是否立即执行
		 */
		buildFn: function(fnStr,returnFn, fire) {
			var fn;
			if(returnFn && fnStr.indexOf('return') != 0)
			{
				fnStr = "return " + fnStr + ";"
			}

			try {
				fn = new Function(this._innerArguments, fnStr);
			} catch (ex) {
				Ccay.Core.log(fnStr);
				throw new Error(ex);

			}
			if (fn && fire)
				return this.callFn(fn);

			return fn;
		},
		/** 使用view内置对象参数运行方法
		 *  @param {string} fnStr : 参数选项,op.name参数名
		 *  @param {boolean} fire : 是否立即执行
		 */
		callFn: function(fn) {
			if ("" == fn) {
				return {};
			}
			return fn.apply(this, this._innerObject);
		},
		/*   		getCurrentView : function(){
   			var view = this.currentView;
   			return view ? view[view.length - 1] : null;
   		},*/
		//根据查找元素
		findElement: function(elem) {
			var jid = typeof(elem) == 'string' ? elem : elem.config.jid;
			return this.find("[" + Jml.Const.JID + "='" + jid + "']");
		},
		find : function(selector){
			return this.dom.find(selector);
		},
		//添加初始化处理委托
		addInitHandler: function(elem, handler) {
			this._InitHandler.add(elem.config.jid, handler);
		},
		//添加初始化处理委托
		removeInitHandler: function(elem) {
			this._InitHandler.remove(elem.config.jid);
		},
		//执行初始化处理委托
		fireInitHandler: function(elem) {
			this._InitHandler.fireAll(null, elem);
		},
		getCurrentView: function() {
			var views = this.currentView,len;
			if (views && (len = views.length)) {
				return views[len - 1];
			}
			return null;
		},
		getCurrentRenderType: function() {
			var view = this.getCurrentView();
			return view && view.renderType;
		}
	}, "view")


	Ccay.Module.load = function(target, url) {
		var template = $.create('div');
		template.ccayLoad(url, function() {
			var page = new(EFactory.get('page'))({
				domTemplate: template,
				target: target,
				url : Ccay.DataHelper.parseUrlParams(url)
			});
			page.compile();
		});
	};

	/** 编译ext元素
	 * FIXME:
	 */
	Jml.compileExt = function(target, ext) {
		$.each(ext, function(key, value) {
			var elem = EFactory.getElem(key);
			if (elem) {
				elem = new elem({
					target: target,
					value: value
				});
				elem.compile();
			}
		});
	};

	/**
	 * 解析template模板
	 *
	 * 1.递归访问dom原属，处理data-role属性的原属
	 * 2.分别调用对应elementd的compile方法
	 */
	Jml.compile = function(elem, template) {
		var page = elem.page;

		function compile(templage) {
			var elemType = templage.attr('data-role');
			if (elemType != null) {
				EFactory.compileElement(elemType == 'ext' ? 'control' : elemType, templage, elem);
			} else { //如果已经遇到role标签，直接忽略子，由框架完成初始化
				var html, line;

				html = templage[0].outerHTML;
				line = html.substring(0, html.indexOf(">") + 1);
				page.builder.pushHtml(line);
				Jml.compileChildNodes(elem, templage);
				if ((line = html.match(Const.END_TAG_REGEXP))) {
					page.builder.pushHtml(line[0]);
				}
			}
		}
		compile(template || elem.domTemplate);
		return elem.builder;
	};
	/**
	 * 解析template模板的子元素
	 *
	 */
	Jml.compileChildNodes = function(elem, template) {
		var page = elem.page;
		(template || elem.domTemplate).contents().each(function() {
			if (this.nodeType == 1) {
				Jml.compile(elem, $(this));
			} else {
				//其他元素，原样输出
				page.builder.pushHtml($(this).text());
			}
		});
	};

	/**
	 *  Function Builder工厂类
	 */
	var FunctionBuilder = $.IObject({
		init: function() {
			this.array = ["var _s = [];"];
		},
		pushCode: function(code) {
			this.array.push(code);
		},
		pushHtml: function(html, config) {
			if (html) {
				config && (html = html.formatText(config));
				this.array.push("_s.push(\"" + JmlHelper.formatSpaceChar(html) + "\");");
			}
		},
		compile: function(params) {
			this.array.push("return _s.join('');\n");
			return new Function(params, this.array.join('\n'))
		}
	});

	/**
	 *  返回空的的对象
	 */
	Jml.noop = function() {
		return {};
	}
	/**
	 *  Config Loader工厂类
	 */
	Jml.ConfigLoader = $.IObject({
		init: function(template, page) {
			this.jid = Jml.newJID();
			this.template = template;
			this.page = page;
			template && this.load();
		},
		buildHtmlAttr: function() {
			if (this.prop) {
				var arrAttr = [];
				//为了给button绑定click事件
				if (this.role != "button") {
					$.each(this.prop, function(name, value) {
						value != null && arrAttr.push(name + '="' + Helper.escape(value) + '"');
					})
				}
				//添加jid
				this.jid && arrAttr.push(Jml.Const.JID + '="' + this.jid + '"');
				this.htmlAttr = {
					prop: arrAttr.join(' ')
				};
			}
		},
		load: function(template) {
			this._compiled = false;
			this._executed = false;
			template && (this.template = template);
			$.extend(this, Ccay.Jml.loadConfig(this.template, this.page));
			return this;
		},
		compile: function() {
			if (this._compiled) {
				return this;
			}
			this.option = this.option ? this.page.buildFn('{' + this.option + '}',true) : Jml.noop;
			this.extOption = this.extOption ? this.page.buildFn(this.extOption,true) : Jml.noop;
			this.event = this.event ? this.page.buildFn(this.event,true) : Jml.noop;
			var ext = [];
			$.each(this.ext, function(key, value) {
				ext.push(key + ':{' + value.join(',') + '}');
			});
			this.ext = ext.length ? this.page.buildFn('{' + ext.join(',') + '}',true) : Jml.noop;
			this._compiled = true;
			return this;
		},
		execute: function() {
			if (this._executed) {
				return this;
			}
			this.compile();
			$.isFunction(this.option) && (this.option = this.page.callFn(this.option));
			$.isFunction(this.extOption) && (this.extOption = this.page.callFn(this.extOption));
			var data = this.option;
			$.extend(true,this.option,this.extOption);
//			$.each(this.extOption, function(key, value) {
//				Helper.setObj(key, data, value);
//			});
			$.isFunction(this.event) && (this.event = this.page.callFn(this.event));
			$.isFunction(this.ext) && (this.ext = this.page.callFn(this.ext));
			this._executed = true;
			return this;
		}
	});

	/**
	 * 解析template模板的配置信息
	 *
	 */
	Ccay.Jml.loadConfig = function(templage, page) {
		var attr = {}, option = [],
			extOption = [],
			event = [],
			bingings, behavior, ext = {}, role = null;
		$.each(templage[0].attributes, function() {
			var name = this.name,
				value = this.value;
			if (Const.DATA_ATTR_REGEXP.test(name)) {
				name = name.substr(5);
				if (name == 'role') {
					role = value;
					return;
				}
				if (name == 'ext') {
					return;
				}
				if (name == 'bindings') {
					bingings = value;
				} else if (name == 'behavior') {
					behavior = value;
				} else if (Const.OPTION_ATTR_REGEXP.test(name)) {
					option.push(JmlHelper.buildProp(name, value));
				} else if (Const.EVENT_ATTR_REGEXP.test(name)) {
					event.push(JmlHelper.buildProp(name, value));
				} else if (Const.EXT_ATTR_REGEXP.test(name)) { //ext扩展属性
					name = name.substr(4), extName = name.split('-')[0];
					ext[extName] = ext[extName] || [];
					ext[extName].push(JmlHelper.buildProp(name, value));
				}
			} else {
				attr[name] = value;
			}
		});

		//扩展子元素可以配置option
		//		templage.children("script").each(function() {
		//			var elem = $(this),type = elem.attr('type');
		//			if(type == 'option'){
		//				extOption.push(elem.text());
		//				elem.remove();
		//			}else if(type == 'event'){
		//				event.push(elem.text());
		//				elem.remove();
		//			}
		//		});

		//查找元素后面的option/script设置
		var script = templage.next("script");
		while (script.length > 0) {
			var type = script.attr('type');
			if (type == 'option') {
				extOption.push(script.text());
				script.remove();
			} else if (type == 'event') {
				event.push(script.text());
				script.remove();
			}
			script = script.next("script");
		}

		return {
			role: role,
			prop: attr,
			option: option.join(','),
			extOption: extOption.join(','),
			event: event.join(','),
			ext: ext,
			bingings: bingings,
			behavior: behavior
		};
	}

	var JmlHelper = {
		/**
		 * 处理字符串中的空白字符
		 */
		formatSpaceChar: function(text) {
			return text.replace(/\\|"|'|\r|\n|\t|\u2028|\u2029/g, function(match) {
				return '\\' + Const.formatSpaces[match];
			});
		},
		buildProp: function(name, value) {
			var path = name.split('-'),
				length = path.length - 1,
				name = '';
			if (length > 0) {
				for (var i = 1; i <= length; i++) {
					name += path[i] + ':{';
					if (i == length) {
						name += value;
					}
					name += '}';
				}
				return name;
			} else {
				return value;
			}
		}
	};
})(Ccay.DataHelper);